<template>
  <div class="containers">

    <div class="canvas" ref='canvas'></div>
    <div class="properties-panel-parent" id="js-properties-panel"></div>
    <div class="buttons">
      <input type="file" ref="fileInput" v-show="false" accept=".bpmn" @change="getFile" />
      <el-button icon="el-icon-folder-opened" type="primary" plain @click="openDiagram">打开bpmn文件</el-button>
      <el-button icon="el-icon-download" type="primary" plain @click="saveDiagram">BPMN diagram</el-button>
      <el-button icon="el-icon-picture" type="primary" plain @click="saveSvg">SVG图片</el-button>
      <el-button icon="el-icon-picture" type="primary" plain @click="localBpmn">log</el-button>
      <el-button type="primary" size="mini" @click="handleUndo">后退</el-button>
      <el-button type="success" size="mini" @click="handleRedo">前进</el-button>
      <el-button type="success" size="mini" @click="zoom(0.1)">放大</el-button>
      <el-button type="success" size="mini" @click="zoom(-0.1)">缩小</el-button>
      <el-button type="success" size="mini" @click="zoom(0)">还原</el-button>
      <el-button type="success" size="mini" @click="clear">清空</el-button>
    </div>
  </div>
</template>

<script>
import BpmnViewer from 'bpmn-js/lib/Viewer';//这个为预览，只需配置container
import Modeler from "bpmn-js/lib/Modeler"; // 引入流程图
import propertiesPanelModule from "bpmn-js-properties-panel"; //  这里引入的是右侧属性栏这个框
import propertiesProviderModule from "bpmn-js-properties-panel/lib/provider/camunda"; // 而这个引入的是右侧属性栏里的内容
import zhCN from "./customTranslate";// 中文
import camundaModdleDescriptor from "camunda-bpmn-moddle/resources/camunda";//外部任务配置
import { xmlStr } from "./mock/xmlStr"
export default {
  data() {
    return {
      modeler: null,
    };
  },
  mounted() {
    // 生成实例
    this.modeler = new Modeler({
      container: this.$refs.canvas,
      keyboard: {//快捷键
        bindTo: window //document
      },
      width: '100%',
      height: '100%',
      propertiesPanel: {
        parent: "#js-properties-panel",
      },
      bpmnRenderer: {
        defaultFillColor: '#fff',
        defaultStrokeColor: 'teal'
      },
      textRenderer: {
        defaultStyle: {
          // fontFamily: '"Nothing You Could Do"',
          // fontWeight: 'bold',
          // fontSize: 12,
          // lineHeight: 16
        },
        externalStyle: {
          // fontSize: 12,
          // lineHeight: 1
        }
      },
      additionalModules: [ // 自定义且与默认扩展包一起使用的模块列表
        propertiesPanelModule, // 右边工具栏
        propertiesProviderModule, // 右边的工具栏
        {
          translate: ["value", zhCN], // 中文
          // zoomScroll: ["value", ""],// 禁用滚轮滚动
          // bendpoints: ["value", ""], // 禁止拖动线
          // paletteProvider: ["value", ""], // 禁用左侧面板
          // contextPadProvider: ["value", ""],// 禁止点击节点出现contextPad
          // labelEditingProvider: ["value", ""] // 禁止双击节点出现label编辑框
        },
      ],
      moddleExtensions: { // 需要用的扩展包
        camunda: camundaModdleDescriptor,
      },
    });

    console.log(this.modeler);
    this.createNewDiagram();// 新增流程定义
    this.bpmnEvent();
  },
  beforeDestroy() {
    this.modeler.destroy()
  },
  methods: {

    //注册节点事件，可以写多个事件
    bpmnEvent() {
      const eventBus = this.modeler.get("eventBus");
      eventBus.on(["element.click", 'element.changed'], (e) => {
        const { element, type } = e;
        // console.log(eventType, element);
        if (!e || !element || !element.parent || element.type === "bpmn:Process") return; //这里我的根元素是bpmn:Process
        if (type === "element.click") {
          console.log(element);
          // this.changeColor(element)
          // this.overlays(element)
          // this.changeAttrs(element)
          this.addMarker(element)
        } else if (type === "element.hover") {
          // 鼠标滑过节点后想要做的处理
          // console.log("鼠标经过节点啦~");
        } else if (type === "element.changed") {
          console.log('元素改变触发');
        }
      });
    },
    // 给图绑定事件，当图有发生改变就会触发这个事件
    addBpmnListener() {
      const that = this
      this.modeler.on('commandStack.changed', function () {
        // that.saveDiagram(function (err, xml) {
        //   console.log(xml) // 这里获取到的就是最新的xml信息
        // })
      })
    },
    // 叠加元素
    overlays(element) {
      var overlays = this.modeler.get('overlays');
      var overlayHtml = document.createElement('div');
      overlayHtml.innerHTML = 'Mixed up the labels?'

      // 添加
      let overlayId = overlays.add(element, {
        position: {
          bottom: 0,
          right: 0
        },
        html: overlayHtml
      });

      // 移除
      overlayHtml.onclick = function (e) {
        alert('someone clicked me');
        overlays.remove(overlayId);
      };
    },
    // 改变属性
    changeAttrs(element) {
      var modeling = this.modeler.get('modeling');
      modeling.updateProperties(element, { id: 'a110' })
    },
    // 添加类名
    addMarker(element) {
      this.modeler.get('canvas').addMarker(element.id, 'addMarker-class')
    },
    // 元素颜色
    changeColor(element) {
      var modeling = this.modeler.get('modeling');
      modeling.setColor([element], {
        stroke: 'green',
        fill: 'yellow'
      });
      // modeling.setColor([element], null); // removing previously set colors
    },
    // 后退
    handleUndo() {
      this.modeler.get("commandStack").undo();
    },
    // 前进
    handleRedo() {
      this.modeler.get("commandStack").redo();
    },
    // 放大缩小
    zoom(num) {
      const newScale = !num ? 1.0 : this.modeler.get('canvas').zoom() + num;
      this.modeler.get('canvas').zoom(newScale)
    },
    localBpmn() {
      console.log(this.modeler);
      console.log(propertiesProviderModule);
      this.modeler.saveXML((err, xml) => {
        console.log(err);
        console.log(xml);
        sessionStorage.setItem("xml", xml);
      });
    },
    // 新增流程定义
    async createNewDiagram() {
      // this.modeler.createDiagram()//创建空白流程图
      // 自定义的xml模板，可以自己修改
      const xml = sessionStorage.getItem("xml");
      try {
        const result = await this.modeler.importXML(xmlStr || xml);
        const { warnings } = result;
        console.log('success !', warnings);
        this.addBpmnListener()
        this.modeler.get('canvas').zoom('fit-viewport', 'auto');//画布剧中
      } catch (err) {
        const { warnings, message } = err;
        console.log('something went wrong:', warnings, message);
      }


    },
    // 打开本地文件，调用input的click事件
    openDiagram() {
      this.$refs.fileInput.click();
    },
    // 打开本地文件
    getFile(e) {
      this.fileList = e.target.files || [];
      if (this.fileList.length === 0) return
      let reader = new FileReader();
      reader.onload = (E) => {
        let xml = E.target.result;
        // 在bpmn实例中导入该本地文件
        this.modeler.importXML(xml, function (err) {
          if (err) {
            console.error(err);
          }
        });
      };
      reader.readAsText(this.fileList[0]);
    },
    // 下载
    setEncoded(name, data) {
      // 将xml或svg作为 URI 组件进行编码
      let encodedData = encodeURIComponent(data);
      // 创建a链接进行下载
      if (data) {
        let a = document.createElement("a");
        a.download = name;
        a.href = "data:application/bpmn20-xml;charset=UTF-8," + encodedData;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
      }
    },
    // 下载bpmn
    saveDiagram() {
      this.modeler.saveXML({ format: true }, (err, xml) => {
        this.setEncoded("diagram.bpmn", err ? null : xml);
      });
    },
    // 下载svg
    saveSvg() {
      this.modeler.saveSVG((err, svg) => {
        this.setEncoded("diagram.svg", err ? null : svg);
      });
    },

    // 通过Id获取节点实例
    getBpmEl(id = "Task_1hcentk") {
      const elementRegistry = this.modeler.get("elementRegistry");
      const el = elementRegistry.get(id);//.getAll()获取全部节点
      console.log(el);
      // this.modeler.modeling.updateLabel('Task_1hcentk','123');
    },
    // 获取流程图内所有指定类型的节点
    getTastType(type = "bpmn:UserTask") {
      const elementRegistry = this.modeler.get("elementRegistry"); //获取所有任务任务
      const taskList = elementRegistry.filter((item) => item.type === type);
      return taskList;
    },
    // 改变节点颜色
    changeColor(el) {
      let modeling = this.modeler.get("modeling");
      modeling.setColor(el, {
        stroke: "green",
        fill: "yellow",
      });
    },
    clear() {
      this.modeler.clear()
    }
  },
};
</script>

<style lang="scss">
/*左边工具栏以及编辑节点的样式*/
@import "~bpmn-js/dist/assets/diagram-js.css";
@import "~bpmn-js/dist/assets/bpmn-font/css/bpmn.css";
@import "~bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css";
@import "~bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
/*右边工具栏样式*/
@import "~bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css";
@import "./custom/index.scss";

.buttons {
  position: absolute;
  bottom: 40px;
  left: 100px;
  padding: 0;
  margin: 0;
  list-style: none;
  & > li {
    display: inline-block;
    margin-right: 10px;
    & > a {
      background: #ddd;
      border: solid 1px #666;
      display: inline-block;
      padding: 5px;
      &.active {
        opacity: 1;
      }
    }
  }
}
.properties-panel-parent {
  width: 260px;
  border-left: 1px solid #ccc;
  overflow: auto;
  position: absolute;
  top: 21px;
  right: 21px;
  height: calc(100% - 40px);
  &:empty {
    display: none;
    &.djs-properties-panel {
      padding-bottom: 70px;
      min-height: 100%;
    }
  }
}

.containers {
  position: absolute;
  background-color: #ffffff;
  width: calc(100% - 20px);
  height: calc(100% - 40px);
}
.canvas {
  width: 100%;
  height: 100%;
}
.panel {
  position: absolute;
  right: 0;
  top: 0;
  width: 300px;
}

// svg修改样式
.addMarker-class .djs-visual > :nth-child(1) {
  stroke: #91d5ff !important; /* color elements as red */
  fill: #e6f7ff !important; /* color elements as red */
  fill-opacity: 0.5 !important;
}
</style>
